use super::query::index_entry::{IndexEntry, IndexEntryImpl};
use crate::config::app_error::{AppError, AppResult};
use crate::extension::index::index::index_entry_container::IndexEntryContainer;
use crate::extension::index::index::indexer_transaction::{ChangeRecord, IndexerTransaction};
use crate::extension::index::index::query::index_attribute::IndexAttributeFactory;
use crate::extension::index::index::query::index_descriptor::IndexDescriptor;
use crate::extension::index::index::query::index_spec::{IndexSpec, OrderType};
use halo_model::{ExtensionGVK, ExtensionOperator, GVK};
use std::borrow::Borrow;
use std::cell::RefCell;
use std::hash::Hash;
use std::sync::Arc;

/// The Indexer is owned by the Extension and is responsible for the lookup and lifetimes of the indexes in a Extension collection. Every Extension has exactly one instance of this class.
/// Callers are expected to have acquired the necessary locks while accessing this interface.
/// To inspect the contents of this Indexer, callers may obtain an iterator from getIndexIterator()
pub trait Indexer {
    type Entry<T>: IndexEntry
    where
        T: ExtensionGVK;
    // 泛型方法，E需要实现Extension trait
    fn index_record<T: ExtensionGVK>(&mut self, extension: T) -> AppResult<()>;

    // 更新索引记录，同上
    fn update_record<T: ExtensionGVK>(&mut self, extension: T) -> AppResult<()>;

    // 移除索引记录，接受一个字符串参数
    fn un_index_record<T: ExtensionGVK>(&mut self, extension_name: &str) -> AppResult<()>;

    // 根据名称查找索引描述符
    fn find_index_by_name<T: ExtensionGVK>(
        &self,
        name: &str,
    ) -> AppResult<Option<&Arc<RefCell<Self::Entry<T>>>>>;

    // 创建索引条目
    fn create_index_entry<T: ExtensionGVK>(&self, descriptor: IndexDescriptor<T>)
        -> Self::Entry<T>;

    // 移除匹配给定条件的所有索引记录
    fn remove_index_records<F, T: ExtensionGVK>(&mut self, match_fn: F) -> AppResult<()>
    where
        F: Fn(&IndexDescriptor<T>) -> bool;

    // 根据索引名称获取索引条目
    fn get_index_entry<T: ExtensionGVK>(
        &self,
        name: &str,
    ) -> AppResult<Arc<RefCell<Self::Entry<T>>>>;

    // 获取所有就绪的索引条目的迭代器
    fn ready_indexes_iterator<T: ExtensionGVK>(
        &self,
    ) -> AppResult<Vec<Arc<RefCell<Self::Entry<T>>>>>;

    // 获取所有索引条目的迭代器
    fn all_indexes_iterator<T: ExtensionGVK>(&self)
        -> AppResult<Vec<Arc<RefCell<Self::Entry<T>>>>>;
}

pub struct DefaultIndexer {
    index_entries: IndexEntryContainer,
}

impl DefaultIndexer {
    pub fn new<T: ExtensionGVK>(old_index_entries: IndexEntryContainer) -> AppResult<Self> {
        let mut index_entries = IndexEntryContainer::new();
        let vec = old_index_entries.iter::<IndexEntryImpl<T>>()?;
        for index_entry in vec {
            index_entries.add::<IndexEntryImpl<T>>(Arc::clone(&index_entry))?;
        }
        let spec1 = IndexSpec::new(
            "metadata.name".to_string(),
            OrderType::ASC,
            true,
            IndexAttributeFactory::simple_attribute(
                "FakeExtension".to_string(),
                |e: &crate::extension::model::user::User| e.get_metadata().get_name(),
            ),
        );
        let a = Arc::new(RefCell::new(IndexEntryImpl::new(IndexDescriptor::new(
            spec1,
        ))));
        let mut vec = Vec::new();
        vec.push(a);
        for x in vec {}
        // for mut index_entry in &index_entries.iter::<IndexEntryImpl<T>>()? {
        //     let index_descriptor = index_entry.borrow().get_index_descriptor();
        //     if !index_descriptor.ready {
        //         return Err(AppError::Err(format!(
        //             "Index descriptor is not ready for: {}",
        //             index_descriptor.spec.name
        //         )));
        //     }
        //     if !index_entries.contains(&index_descriptor.identity())? {
        //         return Err(anyhow::anyhow!(
        //             "Index entry not found for: {}",
        //             index_descriptor.spec.name
        //         )
        //         .into());
        //     }
        // }
        // Ok(DefaultIndexer { index_entries })
        todo!()
    }
}

impl Indexer for DefaultIndexer {
    type Entry<T>
        = IndexEntryImpl<T>
    where
        T: ExtensionGVK;

    fn index_record<T: ExtensionGVK>(&mut self, extension: T) -> AppResult<()> {
        let mut transaction = IndexerTransaction::new();
        if let Ok(()) = transaction.begin() {
            for it in self.do_index_record(extension)? {
                transaction.add(it)?;
            }
            transaction.commit()?;
        } else {
            transaction.rollback()?;
        }
        Ok(())
    }

    fn update_record<T: ExtensionGVK>(&mut self, extension: T) -> AppResult<()> {
        let mut transaction: IndexerTransaction<IndexEntryImpl<T>> = IndexerTransaction::new();
        if let Ok(()) = transaction.begin() {
            self.un_index_record::<T>(&get_object_key(&extension))?;
            self.index_record(extension)?;
            transaction.commit()?;
        } else {
            transaction.rollback()?;
        }
        Ok(())
    }

    fn un_index_record<T: ExtensionGVK>(&mut self, extension_name: &str) -> AppResult<()> {
        let mut transaction: IndexerTransaction<IndexEntryImpl<T>> = IndexerTransaction::new();
        if let Ok(()) = transaction.begin() {
            for it in self.do_un_index_record(extension_name)? {
                transaction.add(it)?;
            }
            transaction.commit()?;
        } else {
            transaction.rollback()?;
        }
        Ok(())
    }

    fn find_index_by_name<T: ExtensionGVK>(
        &self,
        name: &str,
    ) -> AppResult<Option<&Arc<RefCell<IndexEntryImpl<T>>>>> {
        // let entries = self.index_entries.iter::<IndexEntryImpl<T>>()?;
        // let a = entries
        //     .into_iter()
        //     .find(|x| x.borrow().get_index_descriptor().spec.name == name.to_string());
        // Ok(a)
        todo!()
    }

    fn create_index_entry<T: ExtensionGVK>(
        &self,
        descriptor: IndexDescriptor<T>,
    ) -> IndexEntryImpl<T> {
        IndexEntryImpl::new(descriptor)
    }

    fn remove_index_records<F, T: ExtensionGVK>(&mut self, match_fn: F) -> AppResult<()>
    where
         F: Fn(&IndexDescriptor<T>) -> bool,
    {
        let vec = self
            .index_entries
            .remove_fn::<_, IndexEntryImpl<T>>(match_fn)?;
        for mut index_entry in vec {
            {
                index_entry.borrow_mut().clear();
            }
            if let Some(index_entry) = Arc::into_inner(index_entry) {
                let index_entry = index_entry.into_inner();
                let descriptor = index_entry.get_inner_index_descriptor();
                self.index_entries
                    .add::<IndexEntryImpl<T>>(Arc::new(RefCell::new(
                        self.create_index_entry(descriptor),
                    )))?;
            }
        }
        Ok(())
    }

    fn get_index_entry<T: ExtensionGVK>(
        &self,
        name: &str,
    ) -> AppResult<Arc<RefCell<IndexEntryImpl<T>>>> {
        // if let Some(index_entry) = self.find_index_by_name(name)? {
        //     if !index_entry.borrow().get_index_descriptor().ready {
        //         return Err(anyhow::anyhow!("Index [{}] is not ready, Please wait for more time or check the index status. ", name).into());
        //     }
        //     Ok(Arc::clone(index_entry))
        // } else {
        //     Err(anyhow::anyhow!("Index not found for fieldPath: [{}],make sure you have created an index for this field.", name).into())
        // }
        todo!()
    }

    fn ready_indexes_iterator<T: ExtensionGVK>(
        &self,
    ) -> AppResult<Vec<Arc<RefCell<IndexEntryImpl<T>>>>> {
        // let mut ready_indexes = Vec::new();
        // let entries = self.index_entries.iter::<IndexEntryImpl<T>>()?;
        // for x in entries {
        //     if x.borrow().get_index_descriptor().ready {
        //         ready_indexes.push(Arc::clone(&x));
        //     }
        // }
        // Ok(ready_indexes)
        todo!()
    }

    fn all_indexes_iterator<T: ExtensionGVK>(
        &self,
    ) -> AppResult<Vec<Arc<RefCell<IndexEntryImpl<IndexEntryImpl<T>>>>>> {
        // let mut ready_indexes = Vec::new();
        // let entries = self.index_entries.iter::<IndexEntryImpl<T>>()?;
        // for x in entries {
        //     ready_indexes.push(Arc::clone(&x));
        // }
        // Ok(ready_indexes)

        todo!()
    }
}

impl DefaultIndexer {
    fn do_index_record<T: ExtensionGVK>(
        &mut self,
        extension: T,
    ) -> AppResult<Vec<ChangeRecord<IndexEntryImpl<T>>>> {
        // let mut change_records = Vec::new();
        // let entries = self.index_entries.iter::<IndexEntryImpl<T>>()?;
        // for mut index_entry in entries {
        //     let index_descriptor = index_entry.borrow_mut().get_index_descriptor();
        //     let index_func = &index_descriptor.spec.index_func;
        //     let index_keys = index_func.get_values(&extension);
        //     let object_key = extension.get_metadata().get_name();
        //     for key in index_keys {
        //         let arc = Arc::clone(&index_entry);
        //         change_records.push(ChangeRecord::on_add(arc, key, object_key.clone()));
        //     }
        // }
        // Ok(change_records)
        todo!()
    }

    fn do_un_index_record<T: ExtensionGVK>(
        &mut self,
        extension_name: &str,
    ) -> AppResult<Vec<ChangeRecord<IndexEntryImpl<T>>>> {
        let mut change_records = Vec::new();
        let extension_name = extension_name.to_string();
        let entries = self.index_entries.iter::<IndexEntryImpl<T>>()?;
        for index_entry in entries {
            for (key, value) in index_entry.borrow_mut().entries() {
                if *value == extension_name {
                    change_records.push(ChangeRecord::on_remove(
                        Arc::clone(&index_entry),
                        key.clone(),
                        extension_name.clone(),
                    ));
                }
            }
        }
        Ok(change_records)
    }
}

fn get_object_key<E: ExtensionGVK>(extension: &E) -> String {
    extension.get_metadata().get_name()
}

#[cfg(test)]
mod default_indexer_tests {
    use super::*;
    use crate::config::app_error::AppError;
    use crate::extension::index::index::query::index_attribute::{
        IndexAttributeFactory, IndexAttributeType,
    };
    use crate::extension::index::index::query::index_spec::{IndexSpec, OrderType};
    use crate::tests;
    use crate::tests::index_view_data_set::FakeExtension;
    use halo_model::Metadata;
    use pretty_assertions::assert_eq;

    #[test]
    fn ready_indexes_iterator() {
        let mut index_container = IndexEntryContainer::new();
        let mut descriptor = IndexDescriptor::new(get_name_index_spec());
        descriptor.ready = true;

        let name_index_entry = Arc::new(RefCell::new(IndexEntryImpl::new(descriptor)));
        index_container
            .add::<IndexEntryImpl<FakeExtension>>(name_index_entry)
            .unwrap();

        let indexer = DefaultIndexer::new(index_container).unwrap();

        let iterator = indexer.ready_indexes_iterator::<FakeExtension>()?;
        assert_eq!(iterator.len(), 1);

        {
            for mut ele in indexer.ready_indexes_iterator::<FakeExtension>() {
                ele.borrow_mut().set_ready(false);
            }
        }

        assert_eq!(indexer.ready_indexes_iterator()?.len(), 0);
    }

    #[test]
    fn remove_index_record() {
        let name_spec = get_name_index_spec();
        let mut descriptor = IndexDescriptor::new(name_spec);
        descriptor.ready = true;
        let mut index_container = IndexEntryContainer::new();
        let index_entry = Arc::new(RefCell::new(IndexEntryImpl::new(descriptor)));
        index_container
            .add::<IndexEntryImpl<FakeExtension>>(index_entry.clone())
            .unwrap();

        let mut indexer = DefaultIndexer::new(index_container).unwrap();

        indexer.index_record(create_fake_extension()).unwrap();

        let contains = tests::contains_entry(
            index_entry.borrow().entries(),
            "fake-extension_index",
            "fake-extension_index",
        );

        assert!(contains);

        indexer.remove_index_records(|_| true).unwrap();

        assert_eq!(index_entry.borrow().entries().count(), 0);
    }

    #[test]
    fn create_index_entry() {
        let name_spec = get_name_index_spec();
        let mut descriptor = IndexDescriptor::new(name_spec);
        descriptor.ready = true;
        let mut index_container = IndexEntryContainer::new();
        index_container
            .add::<IndexEntryImpl<FakeExtension>>(Arc::new(RefCell::new(IndexEntryImpl::new(
                descriptor,
            ))))
            .unwrap();

        let indexer = DefaultIndexer::new(index_container).unwrap();

        let name_spec = get_name_index_spec();
        let mut descriptor = IndexDescriptor::new(name_spec);
        descriptor.ready = true;
        let index_entry = indexer.create_index_entry(descriptor);
    }

    #[test]
    fn find_index_by_name() {
        let mut index_container = IndexEntryContainer::new();
        // add email before name
        let mut email_descriptor = IndexDescriptor::new(get_index_spec(
            "email",
            false,
            IndexAttributeFactory::simple_attribute(
                "FakeExtension".to_string(),
                |e: &FakeExtension| e.email.clone(),
            ),
        ));
        email_descriptor.ready = true;
        let email_index_entry = IndexEntryImpl::new(email_descriptor);
        let email_index_entry = Arc::new(RefCell::new(email_index_entry));

        let mut descriptor = IndexDescriptor::new(get_name_index_spec());
        descriptor.ready = true;
        let name_index_entry = IndexEntryImpl::new(descriptor);
        let name_index_entry = Arc::new(RefCell::new(name_index_entry));

        index_container
            .add::<IndexEntryImpl<FakeExtension>>(email_index_entry.clone())
            .unwrap();
        index_container
            .add::<IndexEntryImpl<FakeExtension>>(name_index_entry.clone())
            .unwrap();

        let mut indexer = DefaultIndexer::new(index_container).unwrap();

        let found_name_descriptor = indexer.find_index_by_name("metadata.name");
        assert!(found_name_descriptor?.is_some());
        // assert_eq!(found_name_descriptor.unwrap(), name_index_entry);
        let found_email_descriptor = indexer.find_index_by_name("email");
        assert!(found_email_descriptor?.is_some());
    }

    #[test]
    fn update_record_with_exception_should_rollback() {
        let mut index_container = IndexEntryContainer::new();
        // add email before name
        let mut email_descriptor = IndexDescriptor::new(get_index_spec(
            "email",
            false,
            IndexAttributeFactory::simple_attribute(
                "FakeExtension".to_string(),
                |e: &FakeExtension| e.email.clone(),
            ),
        ));
        email_descriptor.ready = true;
        let email_index_entry = IndexEntryImpl::new(email_descriptor);
        let email_index_entry = Arc::new(RefCell::new(email_index_entry));

        let mut descriptor = IndexDescriptor::new(get_name_index_spec());
        descriptor.ready = true;
        let name_index_entry = IndexEntryImpl::new(descriptor);
        let name_index_entry = Arc::new(RefCell::new(name_index_entry));

        index_container
            .add::<IndexEntryImpl<FakeExtension>>(email_index_entry.clone())
            .unwrap();
        index_container
            .add::<IndexEntryImpl<FakeExtension>>(name_index_entry.clone())
            .unwrap();

        let mut indexer = DefaultIndexer::new(index_container).unwrap();
        let fake_extension = create_fake_extension();
        indexer.index_record(fake_extension).unwrap();
        assert_eq!(email_index_entry.clone().borrow().entries().count(), 1);
        assert!(email_index_entry.borrow().entries().any(|(key, value)| {
            (*key) == "fake-email".to_string() && (*value) == "fake-extension_index".to_string()
        }));

        assert_eq!(name_index_entry.clone().borrow().entries().count(), 1);
        assert!(name_index_entry.borrow().entries().any(|(key, value)| {
            (*key) == "fake-extension_index".to_string()
                && (*value) == "fake-extension_index".to_string()
        }));
        let mut fake_extension = create_fake_extension();
        fake_extension.email = "email-2".to_string();
        indexer.update_record(fake_extension).unwrap();

        assert_eq!(email_index_entry.clone().borrow().entries().count(), 1);
        let contains = email_index_entry.borrow().entries().any(|(key, value)| {
            (*key) == "email-2".to_string() && (*value) == "fake-extension_index".to_string()
        });
        assert!(contains);

        assert_eq!(name_index_entry.clone().borrow().entries().count(), 1);
        let contains = name_index_entry.borrow().entries().any(|(key, value)| {
            (*key) == "fake-extension_index".to_string()
                && (*value) == "fake-extension_index".to_string()
        });
        assert!(contains);

        let mut fake_extension = create_fake_extension_name("fake-extension_index-2");
        fake_extension.email = "email-2".to_string();
        indexer.update_record(fake_extension).unwrap();
        let contains = email_index_entry.borrow().entries().any(|(key, value)| {
            (*key) == "email-2".to_string() && (*value) == "fake-extension_index".to_string()
        });
        assert!(contains);

        let contains = email_index_entry.borrow().entries().any(|(key, value)| {
            (*key) == "email-2".to_string() && (*value) == "fake-extension_index-2".to_string()
        });
        assert!(contains);

        let contains = name_index_entry.borrow().entries().any(|(key, value)| {
            (*key) == "fake-extension_index".to_string()
                && (*value) == "fake-extension_index".to_string()
        });
        assert!(contains);
        let contains = name_index_entry.borrow().entries().any(|(key, value)| {
            (*key) == "fake-extension_index-2".to_string()
                && (*value) == "fake-extension_index-2".to_string()
        });
        assert!(contains);
    }

    #[test]
    fn index_record_with_exception_should_rollback() {
        let mut index_container = IndexEntryContainer::new();
        let mut email_descriptor = IndexDescriptor::new(get_index_spec(
            "email",
            false,
            IndexAttributeFactory::simple_attribute(
                "FakeExtension".to_string(),
                |e: &FakeExtension| e.email.clone(),
            ),
        ));
        email_descriptor.ready = true;
        let email_index_entry = IndexEntryImpl::new(email_descriptor);

        let mut descriptor = IndexDescriptor::new(get_name_index_spec());
        descriptor.ready = true;
        let name_index_entry = IndexEntryImpl::new(descriptor);

        let email_index_entry = Arc::new(RefCell::new(email_index_entry));
        let name_index_entry = Arc::new(RefCell::new(name_index_entry));
        index_container
            .add::<IndexEntryImpl<FakeExtension>>(email_index_entry.clone())
            .unwrap();
        index_container
            .add::<IndexEntryImpl<FakeExtension>>(name_index_entry.clone())
            .unwrap();

        let mut indexer = DefaultIndexer::new(index_container).unwrap();
        indexer.index_record(create_fake_extension()).unwrap();

        assert_eq!(email_index_entry.borrow().entries().count(), 1);
        assert_eq!(name_index_entry.borrow().entries().count(), 1);

        let mut fake2 = create_fake_extension();
        fake2.email = "email-2".to_string();
        let result = indexer.index_record(fake2);
        assert!(result.is_err());

        if let Err(e) = result {
            match e {
                AppError::DuplicateNameError(msg) => {
                    assert_eq!(msg, "The value [fake-extension_index] is already exists for unique index [metadata.name].".to_string());
                }
                // AppError::AnyHow(e) => { assert_eq!(e.to_string(), "The value [fake-extension_index] is already exists for unique index [metadata.name].".to_string()) }
                e => {
                    panic!("Unexpected error type: {:?}", e);
                }
            }
        }

        // should be rollback email-2 key
        assert_eq!(email_index_entry.borrow().entries().count(), 1);
        assert_eq!(name_index_entry.borrow().entries().count(), 1);
    }

    fn create_index_descriptors1() -> Vec<IndexDescriptor<FakeExtension>> {
        let mut descriptor = IndexDescriptor::new(get_name_index_spec());
        descriptor.ready = true;

        let mut email_descriptor = IndexDescriptor::new(get_index_spec(
            "email",
            false,
            IndexAttributeFactory::simple_attribute(
                "FakeExtension".to_string(),
                |e: &FakeExtension| e.email.clone(),
            ),
        ));
        email_descriptor.ready = true;

        let index_descriptors = vec![descriptor, email_descriptor];
        index_descriptors
    }

    #[test]
    fn index_record() {
        let descriptor = get_descriptor();
        let mut index_container = IndexEntryContainer::new();
        index_container
            .add::<IndexEntryImpl<FakeExtension>>(Arc::new(RefCell::new(IndexEntryImpl::new(
                descriptor,
            ))))
            .unwrap();

        let mut indexer = DefaultIndexer::new(index_container).unwrap();
        indexer.index_record(create_fake_extension()).unwrap();

        let iterator = indexer.all_indexes_iterator()?;
        assert!(!iterator.is_empty());
        let index_entry = &iterator[0].borrow();
        let entries = index_entry.entries();
        assert_eq!(entries.count(), 1);

        let contains = index_entry.entries().any(|(key, value)| {
            (**key) == "fake-extension_index".to_string()
                && (**value) == "fake-extension_index".to_string()
        });
        assert!(contains);
    }

    fn get_descriptor() -> IndexDescriptor<FakeExtension> {
        let name_index = get_name_index_spec();
        let mut descriptor = IndexDescriptor::new(name_index);
        descriptor.ready = true;
        descriptor
    }

    #[test]
    fn get_object_key_test() {
        let fake = create_fake_extension();
        assert_eq!(
            get_object_key(&fake).to_string(),
            "fake-extension_index".to_string()
        );
    }

    #[test]
    fn get_index_entry_test() {
        let spec = get_name_index_spec();
        let mut descriptor = IndexDescriptor::new(spec);
        descriptor.ready = true;
        let mut index_container = IndexEntryContainer::new();
        index_container
            .add::<IndexEntryImpl<FakeExtension>>(Arc::new(RefCell::new(IndexEntryImpl::new(
                descriptor,
            ))))
            .unwrap();

        let default_indexer = DefaultIndexer::new(index_container).unwrap();

        let index_entry = default_indexer.get_index_entry("not - exist");

        assert!(index_entry.is_err());

        let index_entry = default_indexer.get_index_entry("metadata.name");
        assert!(index_entry.is_ok());
    }

    #[test]
    fn constructor_with_exception() {
        let spec = get_name_index_spec();

        let index_container = IndexEntryContainer::new();

        let default_indexer = DefaultIndexer::new::<FakeExtension>(index_container);
        assert!(default_indexer.is_ok());

        let index_container = IndexEntryContainer::new();
        let default_indexer = DefaultIndexer::new::<FakeExtension>(index_container);
        assert!(default_indexer.is_ok());
    }

    #[test]
    fn constructor() {
        let spec = get_name_index_spec();
        let mut descriptor = IndexDescriptor::new(spec);
        descriptor.ready = true;

        let mut index_container = IndexEntryContainer::new();
        index_container
            .add::<IndexEntryImpl<FakeExtension>>(Arc::new(RefCell::new(IndexEntryImpl::new(
                descriptor,
            ))))
            .unwrap();

        DefaultIndexer::new(index_container).unwrap();
    }

    fn get_name_index_spec() -> IndexSpec<FakeExtension> {
        get_index_spec(
            "metadata.name",
            true,
            IndexAttributeFactory::simple_attribute(
                "FakeExtension".to_string(),
                |e: &FakeExtension| e.get_metadata().get_name().clone(),
            ),
        )
    }

    fn get_index_spec<T: ExtensionGVK>(
        name: &str,
        unique: bool,
        index_func: IndexAttributeType<T>,
    ) -> IndexSpec<T> {
        IndexSpec::new(name.to_string(), OrderType::ASC, unique, index_func)
    }

    fn create_fake_extension() -> FakeExtension {
        let mut meta = Metadata::default();
        meta.set_name("fake-extension_index".to_string());
        let mut extension = FakeExtension::new();
        extension.email = "fake-email".to_string();
        extension.tags = Default::default();

        extension
    }
    fn create_fake_extension_name(name: &str) -> FakeExtension {
        let mut meta = Metadata::default();
        meta.set_name(name.to_string());
        let mut extension = FakeExtension::new();
        extension.email = "fake-email".to_string();
        extension.tags = Default::default();
        extension
    }
}
